<?php

namespace app\common;

/**
 * 随机生成类
 */
class Common
{

    /**
     * 生成数字和字母
     *
     * @param int $len 长度
     * @return string
     */
    public static function alnum($len = 6)
    {
        return self::build('alnum', $len);
    }

    /**
     * 仅生成字符
     *
     * @param int $len 长度
     * @return string
     */
    public static function alpha($len = 6)
    {
        return self::build('alpha', $len);
    }

    /**
     * 生成指定长度的随机数字
     *
     * @param int $len 长度
     * @return string
     */
    public static function numeric($len = 4)
    {
        return self::build('numeric', $len);
    }

    /**
     * 数字和字母组合的随机字符串
     *
     * @param int $len 长度
     * @return string
     */
    public static function nozero($len = 4)
    {
        return self::build('nozero', $len);
    }

    /**
     * 能用的随机数生成
     * @param string $type 类型 alpha/alnum/numeric/nozero/unique/md5/encrypt/sha1
     * @param int $len 长度
     * @return string
     */
    public static function build($type = 'alnum', $len = 8)
    {
        switch ($type)
        {
            case 'alpha':
            case 'alnum':
            case 'numeric':
            case 'nozero':
                switch ($type)
                {
                    case 'alpha':
                        $pool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
                        break;
                    case 'alnum':
                        $pool = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
                        break;
                    case 'numeric':
                        $pool = '0123456789';
                        break;
                    case 'nozero':
                        $pool = '123456789';
                        break;
                }
                return substr(str_shuffle(str_repeat($pool, ceil($len / strlen($pool)))), 0, $len);
            case 'unique':
            case 'md5':
                return md5(uniqid(mt_rand()));
            case 'encrypt':
            case 'sha1':
                return sha1(uniqid(mt_rand(), TRUE));
        }
    }

    /**
     * 根据数组元素的概率获得键名
     *
     * @param array $ps array('p1'=>20, 'p2'=>30, 'p3'=>50);
     * @param array $num 默认为1,即随机出来的数量
     * @param array $unique 默认为true,即当num>1时,随机出的数量是否唯一
     * @return mixed 当num为1时返回键名,反之返回一维数组
     */
    public static function lottery($ps, $num = 1, $unique = true)
    {
        if (!$ps)
        {
            return $num == 1 ? '' : [];
        }
        if ($num >= count($ps) && $unique)
        {
            $res = array_keys($ps);
            return $num == 1 ? $res[0] : $res;
        }
        $max_exp = 0;
        $res = [];
        foreach ($ps as $key => $value)
        {
            $value = substr($value, 0, stripos($value, ".") + 6);
            $exp = strlen(strchr($value, '.')) - 1;
            if ($exp > $max_exp)
            {
                $max_exp = $exp;
            }
        }
        $pow_exp = pow(10, $max_exp);
        if ($pow_exp > 1)
        {
            reset($ps);
            foreach ($ps as $key => $value)
            {
                $ps[$key] = $value * $pow_exp;
            }
        }
        $pro_sum = array_sum($ps);
        if ($pro_sum < 1)
        {
            return $num == 1 ? '' : [];
        }
        for ($i = 0; $i < $num; $i++)
        {
            $rand_num = mt_rand(1, $pro_sum);
            reset($ps);
            foreach ($ps as $key => $value)
            {
                if ($rand_num <= $value)
                {
                    break;
                }
                else
                {
                    $rand_num -= $value;
                }
            }
            if ($num == 1)
            {
                $res = $key;
                break;
            }
            else
            {
                $res[$i] = $key;
            }
            if ($unique)
            {
                $pro_sum -= $value;
                unset($ps[$key]);
            }
        }
        return $res;
    }

    /**
     * 获取全球唯一标识
     * @return string
     */
    public static function uuid()
    {
        return sprintf(
                '%04x%04x-%04x-%04x-%04x-%04x%04x%04x', mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0x0fff) | 0x4000, mt_rand(0, 0x3fff) | 0x8000, mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
        );
    }


    /**
     * 生成唯一code
     */
    public function code(){

    }



   /**
     * 创建子节点树形数组
     * 参数
     * $ar 数组，邻接列表方式组织的数据
     * $id 数组中作为主键的下标或关联键名
     * $pid 数组中作为父键的下标或关联键名
     * 返回 多维数组
     **/
    public function find_child($ar, $id='id', $pid='parent_id') {
        foreach($ar as $v){
            $tree[$v[$id]] = $v;
            if(empty($tree[$v[$id]]['permission']) ){
                unset($tree[$v[$id]]['permission']);
            }
        }
        foreach ($tree as $k => $item){
            if($item[$pid]) {
                $tree[$item[$pid]]['child'][$item[$id]] =$tree[$k];
                unset($tree[$k]);
            }
        }
        return $tree;
    }


    //树形递归
    public function genTree($items,$pid ="pid") {
        $map  = [];
        $tree = [];   
        foreach ($items as &$it){
            $map[$it['id']] = &$it; 
        }  
        //数据的ID名生成新的引用索引树
        foreach ($items as &$it){
            $parent = &$map[$it[$pid]];
            if($parent) {
                $parent['children'][] = &$it;
            }else{
                $tree[] = &$it;
            }
        }
        return $tree;
    }


    /**
     * 数组层级缩进转换
     * @param array $array 源数组
     * @param int   $pid
     * @param int   $level
     * @return array
     */
    function array2level($array, $pid = 0, $level = 1)
    {
        static $list = [];
        foreach ($array as $v) {
            if ($v['pid'] == $pid) {
                $v['level'] = $level;
                $list[]     = $v;
                array2level($array, $v['id'], $level + 1);
            }
        }
        return $list;
    }


    /**
     * 创建支付订单编号
     */
    public function createOutTradeNo($data = ''){ 
        global $redis;  
        $order_no = $redis->get("six_shop_bfd".date("Y/m/d"));
        if (empty($order_no)) {
            $redis->set("six_shop_bfd".date("Y/m/d"),1000);
            $order_no = $redis->get("six_shop_bfd".date("Y/m/d"));
        } else {
            $order_no = $order_no + 1;
            $redis->set("six_shop_bfd".date("Y/m/d"), $order_no);
        }
        if($data != ''){
            $no = $data.time().rand(1000, 9999).$order_no;
        }else{
            $no = time().rand(1000, 9999).$order_no;
        }
        return $no;
    }



    /**
     * 二维数组去重
     */
    public function assoc_unique($arr, $key){
        $tmp_arr = array();
        foreach($arr as $k => $v){
            if(in_array($v[$key], $tmp_arr)){
                unset($arr[$k]);
            }else {
                $tmp_arr[] = $v[$key];
            }
        }
        sort($arr);
        return $arr;
    }



    /**
     * 生成token
     */
    public function createToken(){
        $token = sprintf(
                '%04x%04x-%04x-%04x-%04x-%04x%04x%04x', mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0x0fff) | 0x4000, mt_rand(0, 0x3fff) | 0x8000, mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
        );
        return $token;
    }



    /**
     *
     * 获取时间
     * @param data 1=按月，2=按周，3=按季度，4=按年
     * @param number 返回下标
     * @param count 计算多久的时间 默认6次
     *
     */
    public function getTime($date = 1,$number = '',$count = 6){
        $start = [];
        $stop = [];
        if($date == 1){
            $cyear = floor(date("Y",time()));
            $cMonth = floor(date("m",time()));
            for($i=0;$i<$count;$i++){
                $nMonth = $cMonth-$i;
                $cyear = $nMonth == 0 ? ($cyear-1) : $cyear;
                $nMonth = $nMonth <= 0 ? 12+$nMonth : $nMonth;
                $date = $cyear."-".$nMonth."-1";
                $firstday = date('Y-m-01', strtotime($date))." 00:00:00";
                $lastday = date('Y-m-t', strtotime($date))." 23:59:59";
                $start[] =  $firstday;
                $stop[] = $lastday;
            }
        }
        if($date == 2){
            $today = date('N'); //今天周几
            $mon = date('Y-m-d', strtotime("-" . ($today - 1) . "day")); //这周 周一是哪天
            $sun = date('Y-m-d', strtotime($mon . '+ 6 days')); //这周 周日那一天
            for ($i = 0; $i < 5; $i++) {
                $start[] = $mon = date('Y-m-d', strtotime($mon . '- 7 days'))." 00:00:00";
                $stop[] = $sun = date('Y-m-d', strtotime($mon . '+ 6 days'))." 23:59:59";
            }
            $start_time = $start[4]." 00:00:00";
            //获取本周开始时间和结束时间
            $sdefaultDate = date("Y-m-d"); 
            //$first =1 表示每周星期一为开始日期 0表示每周日为开始日期 
            $first=1; 
            //获取当前周的第几天 周日是 0 周一到周六是 1 - 6 
            $w=date('w',strtotime($sdefaultDate)); 
            //获取本周开始日期，如果$w是0，则表示周日，减去 6 天 
            $week_start=date('Y-m-d',strtotime("$sdefaultDate -".($w ? $w - $first : 6).' days'))." 00:00:00";
            //本周结束日期 
            $week_end=date('Y-m-d',strtotime("$week_start +6 days"))." 23:59:59";
            array_unshift($start,$week_start);
            array_unshift($stop,$week_end);
        }
        if($date == 3){
            for ($i=0; $i < $count; $i++) { 
                $season = ceil((date('n'))/3)-$i;
                $start[] = date('Y-m-d H:i:s', mktime(0, 0, 0,$season*3-3+1,1,date('Y')));
                $stop[] = date('Y-m-d H:i:s', mktime(23,59,59,$season*3,date('t',mktime(0, 0 , 0,$season*3,1,date("Y"))),date('Y')));
            }
        }
        if($date == 4){
            for ($i=0; $i < $count; $i++) { 
                $year = date('Y',time());
                $start[] = $year-$i."-01-01 00:00:00";
                $stop[] = $year-$i."-12-31 23:59:59";
            }
        }
        if($number == ''){
            $data['start'] = $start;
            $data['stop'] = $stop;
        }else{
            $data['start'] = $start[$number-1];
            $data['stop'] = $stop[$number-1];
        }
        return $data;
    }
}
